#include <stdio.h>
#include <ucontext.h>

ucontext_t uctx[3];
ucontext_t main_ctx;
// 或者 struct ucontext

int count = 0;

// coroutine 1
void fun1(void)
{
    printf("调用函数fun1\n");
    while (count < 20)
    {
        printf("fun1 count[%d] swap fun2\n", ++count);
        swapcontext(&uctx[0], &uctx[1]); // 通过上下文进行函数跳转
    }
}

// coroutine 2
void fun2(void)
{
    printf("调用函数fun2\n");
    while (count < 20)
    {
        printf("fun2 count[%d] swap fun3\n", ++count);
        swapcontext(&uctx[1], &uctx[2]); // 通过上下文进行函数跳转
    }
}

// coroutine 3
void fun3(void)
{
    printf("调用函数fun3\n");
    while (count < 20)
    {
        printf("fun3 count[%d] swap fun1\n", ++count);
        swapcontext(&uctx[2], &uctx[0]); // 通过上下文进行函数跳转
    }
}

// schedule，类似于调度器
int main()
{
    // 设置协程栈,注意类型是char
    char stack1[2048] = {0};
    char stack2[2048] = {0};
    char stack3[2048] = {0};

    // 获取当前上下文
    getcontext(&uctx[0]);
    uctx[0].uc_stack.ss_sp = stack1;
    uctx[0].uc_stack.ss_size = sizeof(stack1);
    // 设置下一次跳转的函数
    uctx[0].uc_link = &main_ctx;    // 作用是切换上下文执行结束后跳转到指定的上下文中
    makecontext(&uctx[0], fun1, 0); // 需要设置下一次跳转函数的uctx上下文和函数指针

    // 获取当前上下文
    getcontext(&uctx[1]);
    uctx[1].uc_stack.ss_sp = stack2;
    uctx[1].uc_stack.ss_size = sizeof(stack2);
    // 设置下一次跳转的函数
    uctx[1].uc_link = &main_ctx;
    makecontext(&uctx[1], fun2, 0);

    // 获取当前上下文
    getcontext(&uctx[2]);
    uctx[2].uc_stack.ss_sp = stack3;
    uctx[2].uc_stack.ss_size = sizeof(stack3);
    // 设置下一次跳转函数和结束后返回的函数
    uctx[2].uc_link = &main_ctx; // 结束后返回main
    makecontext(&uctx[2], fun3, 0);

    // 切换到函数uctx指向的函数
    printf("main swap fun1\n");
    swapcontext(&main_ctx, &uctx[0]);
    printf("\n");
    return 0;
}